class Custom_Weapon_Sword extends UTWeapon;

var ParticleSystem MyParticleEffect;

/**
 * Normal Sword Attack values
 */
var name SwordAttackAnim[3]; // Names of the sword attack animations
var float SwordAttackHitTime[3]; // Start time for tracing and hurting after an attack started
var float SwordAttackDuration[3]; // Duration of a sword attack
var float SwordAttackMovementDuration[3]; // Amount of forward movement when attacking.
var float SwordAttackHitRange[3]; // Range of a normal sword attack
var float SwordAttackHitDamage[3]; // Damage of a normal sword attack if it hits
var int SwordAttackTraces[3]; // The amount of traces to perform during a sword attack, note: Might be about 1 or more off depending on timer settings

/**
 * Spin Attack values
 */
var name SpinAttackAnim; // Name of the Spin Attack animation
var float SpinAttackChargeTime; // Time needed holding the attack button to charge a spin attack
var float SpinAttackHitTime; // Start time for tracing and hurting after the spin attack started
var float SpinAttackDuration; // Duration of the spin attack
var float SpinAttackRange; // Range of the spin attack
var float SpinAttackHitDamage; // Damage of the spin attack if it hits
var bool bSpinned; // True if did a spin attack in the same click as click being released.

/**
 * Combo attack Values
 */
var float SwordCooldownTime; // Sword cooldown time after ending an attack
var float LastSwordAttackTime; // Time the player stopped attacking
var int MaxCombo; // Maximum combo hits
var int ComboIndex; // Index of the current combo
var float NextComboTime[2]; // Time until you can start queuing the next combo

// Shouldn't refire automatically, only register one attack push.
simulated function bool ShouldRefire()
{
	return false;
}


function SpawnEffect()
{
    WorldInfo.MyEmitterPool.SpawnEmitter(MyParticleEffect, UTPawn(Instigator).Location, UTPawn(Instigator).Rotation, self);
}

// Start trying to do a SpinAttack(releasing attack will result in a normal attack if possible)

simulated function FireAmmunition()
{
	local float ChargeTime;

	// Can't do a spin attack if pressing secondary attack or if at final combo
	if(CurrentFireMode != 0 || ComboIndex == MaxCombo - 1)
		return;

	// Stop trying to attack or else this will be called multiple times
	ClearPendingFire(CurrentFireMode);

	// Just set normal charge first
	ChargeTime = SpinAttackChargeTime;

	// If we haven't passed the cooldown yet, increase the charge time
	if(WorldInfo.TimeSeconds - LastSwordAttackTime < SwordCooldownTime)
		ChargeTime += WorldInfo.TimeSeconds - LastSwordAttackTime;

	// Start up the spin attack
	SetTimer(ChargeTime,, nameOf(StartSpinAttack));
	
        SetTimer(ChargeTime + 0.5,, nameOf(SpawnEffect));
}

exec function SkillTypeA()
{
	UTPawn(Instigator).FullBodyAnimSlot.PlayCustomAnim( 'Skill01', 1.2, 0.1, 0.1, false, true );

	// If player then disable player input
	if(Instigator.IsPlayerPawn())
		Custom_PlayerController(Instigator.Controller).IgnoreMoveInput(true);

	// Mark as having spinned, prevents normal attack from happening when attack key is released
	bSpinned = true;

	// Set the start time for the spin hit
	SetTimer(SpinAttackHitTime,, nameOf(DoSpinAttack));

	// Set the end time
	SetTimer(SpinAttackDuration,, nameOf(EndAttack));	
}

exec function SkillTypeB()
{
	UTPawn(Instigator).FullBodyAnimSlot.PlayCustomAnim( 'Skill02', 1.0, 0.1, 0.1, false, true );

	// If player then disable player input
	if(Instigator.IsPlayerPawn())
		Custom_PlayerController(Instigator.Controller).IgnoreMoveInput(true);

	// Mark as having spinned, prevents normal attack from happening when attack key is released
	bSpinned = true;

	// Set the start time for the spin hit
	SetTimer(SpinAttackHitTime,, nameOf(DoSpinAttack));

	// Set the end time
	SetTimer(SpinAttackDuration,, nameOf(EndAttack));
}

exec function SkillTypeC()
{
	UTPawn(Instigator).FullBodyAnimSlot.PlayCustomAnim( 'Skill03', 1.8, 0.1, 0.1, false, true );

	// If player then disable player input
	if(Instigator.IsPlayerPawn())
		Custom_PlayerController(Instigator.Controller).IgnoreMoveInput(true);

	// Mark as having spinned, prevents normal attack from happening when attack key is released
	bSpinned = true;

	// Set the start time for the spin hit
	SetTimer(SpinAttackHitTime,, nameOf(DoSpinAttack));

	// Set the end time
	SetTimer(SpinAttackDuration,, nameOf(EndAttack));
}

// Start a spin attack
function StartSpinAttack()
{
	// Play the animation
	UTPawn(Instigator).FullBodyAnimSlot.PlayCustomAnim(SpinAttackAnim, 1.f,,,,,, SpinAttackDuration);

	// If player then disable player input
	if(Instigator.IsPlayerPawn())
		Custom_PlayerController(Instigator.Controller).IgnoreMoveInput(true);

	// Mark as having spinned, prevents normal attack from happening when attack key is released
	bSpinned = true;

	// Set the start time for the spin hit
	SetTimer(SpinAttackHitTime,, nameOf(DoSpinAttack));

	// Set the end time
	SetTimer(SpinAttackDuration,, nameOf(EndAttack));
}

// Apply damage for a spin attack
function DoSpinAttack()
{
	local Actor TouchActor;

	// Check all actors within weapon range, apply damage only on things that aren't the instigator
	ForEach VisibleCollidingActors(class'Actor', TouchActor, SpinAttackRange, Instigator.Location, true)
	{
		// Skip the pawn using the sword
		if(TouchActor == Instigator || !TouchActor.bCanBeDamaged)
			continue;

		// Apply damage with a momentum direction from Instigator location to TouchActor location
		TouchActor.TakeDamage( SpinAttackHitDamage, Instigator.Controller,
						TouchActor.Location, Normal(TouchActor.Location - Instigator.Location) * 50,
						InstantHitDamageTypes[1],, self);
	}
}

// Overriden to start a normal attack when the mouse is released(if allowed to)
simulated function EndFire(Byte FireModeNum)
{
	local name StartAttackName, EndAttackName;

	// Handle actual EndFire logic
	super.EndFire(FireModeNum);

	// Only primary attack is accepted
	if(FireModeNum != 0)
		return;

	// We're doing a normal attack, because we didn't hold attack long enough for a spin attack.
	ClearTimer(nameOf(StartSpinAttack));

	// If we spinned in the same click before, we should'n do a normal attack
	if(bSpinned)
	{
		// Reset spinned
		bSpinned = false;
		return;
	}

	StartAttackName = nameOf(StartAttack);
	EndAttackName = nameOf(EndAttack);

	// If we're not in the last combo and not in attack start up then we can try doing an attack
	if(ComboIndex < MaxCombo - 1 && !IsTimerActive(StartAttackName))
	{
		// If there's a normal attack active
		if(IsTimerActive(EndAttackName))
		{
			// And the time since the timer was started has exceeded the next combo time, then we can start a new combo attack
			if(GetTimerCount(EndAttackName) >= NextComboTime[ComboIndex])
			{   

				// Start up the timer first, queued to start when end hit should have been called
				SetTimer(GetTimerRate(EndAttackName) - GetTimerCount(EndAttackName),, StartAttackName);

				// Disable end attack, because we've got a new hit coming up
				ClearTimer(EndAttackName);

				// Start a new combo next
				ComboIndex++;
			}
		}
		else
		{
			// If we haven't passed the cooldown yet, queue up the attack
			if(WorldInfo.TimeSeconds - LastSwordAttackTime < SwordCooldownTime)
				SetTimer(WorldInfo.TimeSeconds - LastSwordAttackTime,, StartAttackName);
			else
				StartAttack(); // Start up an attack right away
		}
	}
}

// Start a normal attack
function StartAttack()
{
	// Play the animation
	UTPawn(Instigator).TopHalfAnimSlot.PlayCustomAnim(SwordAttackAnim[ComboIndex], 1.f,,,,,, SwordAttackDuration[ComboIndex]);

	// Start moving during the attack
	StartAttackMovement(SwordAttackHitTime[ComboIndex]);

	// Set the start time for the first hit
	SetTimer(SwordAttackHitTime[ComboIndex],, nameOf(DoAttack));

	// Set the end time
	SetTimer(SwordAttackDuration[ComboIndex],, nameOf(EndAttack));
}

// Apply damage for a normal attack
function DoAttack()
{
	local Vector Direction, StartTrace, EndTrace, HitLocation, HitNormal;
	local Actor HitActor;

	// Direction is the direction the pawn is looking in
	Direction = Vector(Instigator.Rotation);

	// Start a little behind the view location
	StartTrace = Instigator.GetPawnViewLocation() + -Direction * 10;

	// Trace forward by attack range
	EndTrace = Instigator.GetPawnViewLocation() + Direction * SwordAttackHitRange[ComboIndex];

	// Hit all things that can be hurt in sword range
	ForEach TraceActors(class'Actor', HitActor, HitLocation, HitNormal, EndTrace, StartTrace, vect(96, 96, 0))
	{
		// Skip the pawn using the sword
		if(HitActor == Instigator || !HitActor.bCanBeDamaged)
			continue;

		// Apply damage with a momentum direction from Instigator location to HitActor location
		HitActor.TakeDamage( SwordAttackHitDamage[ComboIndex], Instigator.Controller,
						HitActor.Location, Normal(HitActor.Location - Instigator.Location) * 50,
						InstantHitDamageTypes[2],, self);
	}

	// Do another hit soon
	SetTimer((SwordAttackDuration[ComboIndex] - SwordAttackHitTime[ComboIndex]) / SwordAttackTraces[ComboIndex],, nameOf(DoAttack));
}

// Starts up automatic attack movement when attacking
function StartAttackMovement(float Duration)
{
	local Custom_PlayerController Player;

	// If player
	if(Instigator.IsPlayerPawn())
	{
		Player = Custom_PlayerController(Instigator.Controller);

		// Enable automatic movement
		Player.bInSwordAttackMovement = true;

		// Reset so any ignored input attempts are cleared
		Player.ResetPlayerMovementInput();

		// Set up when to stop automatic attack movement
		SetTimer(Duration,, nameOf(StopAttackMovement));
	}
}

// Stops ongoing attack movement and sets player input to be ignored until attack ends

function StopAttackMovement()
{
	local Custom_PlayerController Player;

	// If player
	if(Instigator.IsPlayerPawn())
	{
		Player = Custom_PlayerController(Instigator.Controller);

		// Disable automatic movement
		Player.bInSwordAttackMovement = false;

		// Disable player input
		Player.IgnoreMoveInput(true);
	}
}

// End any ongoing attack
function EndAttack()
{
	// Stop attacking
	ClearTimer(nameOf(DoAttack));

	// If player re-enable player  input
	if(Instigator.IsPlayerPawn())
		Custom_PlayerController(Instigator.Controller).ResetPlayerMovementInput();

	// Reset combo
	ComboIndex = 0;

	// Mark the time we finished the attack
	LastSwordAttackTime = WorldInfo.TimeSeconds;
}

DefaultProperties
{
	// Pickup staticmesh
	Begin Object Name=PickupMesh
		SkeletalMesh=SkeletalMesh'GDC_Materials.Meshes.SK_ExportSword2'
	End Object

	Begin Object class=AnimNodeSequence Name=MeshSequenceA
		bCauseActorAnimEnd=true
	End Object

	// Weapon SkeletalMesh
	Begin Object Name=FirstPersonMesh
		SkeletalMesh=SkeletalMesh'GDC_Materials.Meshes.SK_ExportSword2'
		//AnimSets(0)=AnimSet''
		Animations=MeshSequenceA
		Scale=0.9
		FOV=60.0
	End Object

	SwordAttackAnim(0)=Attack01
	SwordAttackAnim(1)=Attack02
	SwordAttackAnim(2)=Attack03

	SwordAttackHitTime(0)=0.15f
	SwordAttackHitTime(1)=0.15f
	SwordAttackHitTime(2)=0.15f

	SwordAttackDuration(0)=0.5f
	SwordAttackDuration(1)=0.5f
	SwordAttackDuration(2)=0.5f

	SwordAttackMovementDuration(0)=0.2f
	SwordAttackMovementDuration(1)=0.2f
	SwordAttackMovementDuration(2)=0.2f

	SwordAttackHitRange(0)=25.f
	SwordAttackHitRange(1)=25.f
	SwordAttackHitRange(2)=25.f


	SwordAttackHitDamage(0)=15.f
	SwordAttackHitDamage(1)=25.f
	SwordAttackHitDamage(2)=35.f

	SwordAttackTraces(0)=10
	SwordAttackTraces(1)=10
	SwordAttackTraces(2)=10

	SpinAttackAnim=SpinAttack

	SpinAttackChargeTime=0.75f
	SpinAttackHitTime=0.6f
	SpinAttackDuration=1.5f

	SpinAttackRange=200.f
	SpinAttackHitDamage=1005.f

	SwordCooldownTime=0.6f

	MaxCombo=3

	NextComboTime(0)=0.35f // First to second combo
	NextComboTime(1)=0.35f // Second to last combo

	FireInterval(0)=0.05f // Should be really fast to better register clicks for combo's

	InstantHitDamageTypes(0)=class'Custom_DmgType_SwordCut'
	InstantHitDamageTypes(1)=class'Custom_DmgType_SwordCutA'
	InstantHitDamageTypes(2)=class'Custom_DmgType_SwordCutB'

	DefaultAnimSpeed=0.9f

	AttachmentClass=class'Custom_Attachment_Sword'
	       
	PivotTranslation=(Y=-25.0)
	       
	ShotCost(0)=0

	MaxAmmoCount=1
	AmmoCount=1
	
	MyParticleEffect=ParticleSystem'KismetGame_Assets.Effects.P_BlastMark_01'
}

